%{
    #include <stdio.h>
    #include <stdlib.h>

    #include "TableSym.h"//Arbre.h est inclus dans ce fichier

    extern int num_lines;
    extern char* yytext;
        
    int yylex(void);
    void yyerror(char *str);
    void yyerrorFct(char *str);
    void yyerrorTypage(char *str);

    //int yydebug=1;
        
    //définir la racine de l'arbre:
    TREE root;

    //définir la racine de la table des symboles
    FCTSYM symTable;
%}

// définition du type des variables $x
%union{
   int ival;
   char *sval;
   TREE tval;
}

%error-verbose

%token OUT IN AFFECTL AFFECTR SWAP
%token PLUS MINUS TIMES SLASHORDIV MODULO
%token LP RP CL CR COMMA END COLON
%token AND OR NOT
%token EQUAL SMALLER SMALLEQ GREATER GREATEQ
%token IF FI THEN ELSE WHILE DO OD RETURN
%token INT BOOL MATRIX NIL
%token ID NB TRUE FALSE
%token DECL ENDDECL CODE ENDCODE LSD11 ENDLSD11 FCT ENDFCT
%token SET GET CLONE CREATE
%token VAR

//indique la priorite des operateurs
%left AND OR
%left NOT
%left EQUAL SMALLER SMALLEQ GREATER GREATEQ 
%left PLUS MINUS
%left TIMES SLASHORDIV MODULO 
%left LP RP 


//liste des symboles non-Terminaux
%type <tval> ListArg Arg Int Bool Nil
%type <tval> InstructionCode ListInstructionCode ListFonction Fonction CallFonction ListCallArg CallArg
%type <tval> ListInstructionDecl InstructionDecl
%type <tval> ListVar
%type <tval> ExprG ExprD ClauseIf ClauseWhile
%type <tval> Lsd11
%type <tval> Decl Code
%type <tval> Id Nb True False

//symbole de depart
%start Lsd11

%%

Lsd11 : 
        LSD11 COLON Id CR ListFonction ENDLSD11                       {root=createNode(AT_ROOT,0,$3->name,$3->line,NULL,$5,NULL,NULL);}
;

//Quand il ne reste plus qu'un noeud fct à rajouter, il ne crée pas un nouveau noeud lstfct mais directement un noeud fct.

ListFonction : 
        Fonction                        {$$ = $1;}
        | Fonction ListFonction         {$$ = createNode(AT_LISTFCT,0,"",$1->line,$1,$2,NULL,NULL);}
;

Int : 
        INT             {$$ = createNode(AT_RT,0,"int",num_lines,NULL,NULL,NULL,NULL);}
;

Bool : 
        BOOL            {$$ = createNode(AT_RT,0,"bool",num_lines,NULL,NULL,NULL,NULL);}
;

Nil : 
        NIL             {$$ = createNode(AT_RT,0,"nil",num_lines,NULL,NULL,NULL,NULL);}
;


Fonction :
        CL Id LP ListArg RP COLON Int CR Decl Code CL SLASHORDIV Id CR         
                {$$ = createNode(AT_FCT,0,$2->name,$2->line,$4,$7,$9,$10); 
                        if ((strcmp($2->name,$13->name)!=0) || (strcmp($13->name,$2->name)!=0))
                                yyerrorFct($2->name);
                }
        | CL Id LP ListArg RP COLON Bool CR Decl Code CL SLASHORDIV Id CR      
                {$$ = createNode(AT_FCT,0,$2->name,$2->line,$4,$7,$9,$10); 
                        if ((strcmp($2->name,$13->name)!=0) || (strcmp($13->name,$2->name)!=0))
                                yyerrorFct($2->name);
                }                                                                       

        | CL Id LP ListArg RP COLON Nil CR Decl Code CL SLASHORDIV Id CR       
                {$$ = createNode(AT_FCT,0,$2->name,$2->line,$4,$7,$9,$10); 
                        if ((strcmp($2->name,$13->name)!=0) || (strcmp($13->name,$2->name)!=0))
                                yyerrorFct($2->name);
                }
;

CallFonction :
        Id LP ListCallArg RP    {$$ = createNode(AT_CALLFCT,0,"",$1->line,$1,$3,NULL,NULL);}
;

ListCallArg :
                                                {$$=NULL;}
        | CallArg                               {$$ = createNode(AT_LISTCALLARG, 0, "",$1->line,$1, NULL, NULL, NULL);}
        | CallArg COMMA ListCallArg             {$$ = createNode(AT_LISTCALLARG, 0, "",$1->line,$1, $3, NULL, NULL);}
;

CallArg : 
        ExprD   {$$=createNode(AT_CALLARG, 0, "",$1->line, $1, NULL, NULL, NULL);}
;

//comportement different de listfct (cree un listarg d'office)
ListArg :
                                                {$$ = NULL;}
      | Arg                                     {$$ = createNode(AT_LISTARG,0,"",$1->line,$1,NULL,NULL,NULL);}
      | Arg COMMA ListArg                       {$$ = createNode(AT_LISTARG,0,"",$1->line,$1,$3,NULL,NULL);}
;
          
Arg :
        VAR Id COLON INT                        {$$ = createNode(AT_ARGVARINT,0,"",$2->line,$2,NULL,NULL,NULL);}
        | Id COLON INT                          {$$ = createNode(AT_ARGINT,0,"",$1->line,$1,NULL,NULL,NULL);}
        | VAR Id COLON BOOL                     {$$ = createNode(AT_ARGVARBOOL,0,"",$2->line,$2,NULL,NULL,NULL);}
        | Id COLON BOOL                         {$$ = createNode(AT_ARGBOOL,0,"",$1->line,$1,NULL,NULL,NULL);}
        | VAR Id COLON MATRIX                   {$$ = createNode(AT_ARGVARMATRIX,0,"",$2->line,$2,NULL,NULL,NULL);}
        | Id COLON MATRIX                       {$$ = createNode(AT_ARGMATRIX,0,"",$1->line,$1,NULL,NULL,NULL);}
;

ListVar : 
      Id                                        {$$=$1;}
      | Id ListVar                              {$$ = createNode(AT_LISTVAR,0,"",$1->line,$1,$2,NULL,NULL);} 
;

InstructionDecl :
       INT ListVar END                              {$$ = createNode(AT_INT,0,"",$2->line,$2,NULL,NULL,NULL);}
       | BOOL ListVar END                           {$$ = createNode(AT_BOOL,0,"",$2->line,$2,NULL,NULL,NULL);}
       | MATRIX ListVar END                         {$$ = createNode(AT_MATRIX,0,"",$2->line,$2,NULL,NULL,NULL);}
;

Decl : 
        DECL ListInstructionDecl ENDDECL               {$$ = createNode(AT_DECL,0,"",num_lines,$2,NULL,NULL,NULL);}       //attention num line
;

ListInstructionDecl :
                                                    {$$=NULL;}
       | Fonction ListInstructionDecl               {$$ = createNode(AT_ILISTDECL,0,"",$1->line,$1,$2,NULL,NULL);}
       | InstructionDecl ListInstructionDecl        {$$ = createNode(AT_ILISTDECL,0,"",$1->line,$1,$2,NULL,NULL);}
;


ClauseIf :
        IF LP ExprD RP THEN ListInstructionCode FI                            {$$ = createNode(AT_IF,0,"",$3->line,$3,$6,NULL,NULL);}
        | IF LP ExprD RP THEN ListInstructionCode ELSE ListInstructionCode FI {$$ = createNode(AT_IF,0,"",$3->line,$3,$6,$8,NULL);}
;

ClauseWhile :
        WHILE LP ExprD RP DO ListInstructionCode OD                           {$$ = createNode(AT_WHILE,0,"",$3->line,$3,$6,NULL,NULL);}
;

InstructionCode :
        ExprG AFFECTL ExprD END                                 {$$ = createNode(AT_AFFECTL,0,"",$1->line,$1,$3,NULL,NULL);}
        | ExprD AFFECTR ExprG END                               {$$ = createNode(AT_AFFECTL,0,"",$1->line,$3,$1,NULL,NULL);}
        | ExprG SWAP ExprG END                                  {$$ = createNode(AT_SWAP,0,"",$1->line,$1,$3,NULL,NULL);}
        | ClauseIf END                                          {$$ = $1;}
        | ClauseWhile END                                       {$$ = $1;}
        | OUT AFFECTL ExprD END                                 {$$ = createNode(AT_OUT,0,"",$3->line,$3,NULL,NULL,NULL);}
        | CREATE LP Id COMMA ExprD COMMA ExprD RP END           {$$ = createNode(AT_CREATE,0,"",$3->line,$3,$5,$7,NULL);}
        | SET LP Id COMMA ExprD COMMA ExprD COMMA ExprD RP END  {$$ = createNode(AT_SET,0,"",$3->line,$3,$5,$7,$9);}
        | CLONE LP Id COMMA Id RP END                           {$$ = createNode(AT_CLONE,0,"",$3->line,$3,$5,NULL,NULL);}
        | RETURN LP ExprD RP END                                {$$ = createNode(AT_RETURN,0,"",$3->line,$3,NULL,NULL,NULL);}
        | CallFonction END                                      {$$ = $1;}

;

ListInstructionCode :
                                                {$$=NULL;}
        | InstructionCode ListInstructionCode   {$$ = createNode(AT_ILISTCODE,0,"",num_lines,$1,$2,NULL,NULL);}
;

Code :
        CODE ListInstructionCode ENDCODE    {$$ = createNode(AT_CODE,0,"",num_lines,$2,NULL,NULL,NULL);}
;

Id : ID           {$$=createNode(AT_ID,0,yylval.sval,num_lines,NULL,NULL,NULL,NULL);}
;

Nb :
        NB {$$=createNode(AT_NBPOS,yylval.ival,"NBPOS",num_lines,NULL,NULL,NULL,NULL);}
        | MINUS NB {$$=createNode(AT_NBNEG,-1*yylval.ival,"NBNEG",num_lines,NULL,NULL,NULL,NULL);}
;

True : TRUE       {$$=createNode(AT_BOOL,1,"TRUE",num_lines,NULL,NULL,NULL,NULL);}
;

False : FALSE     {$$=createNode(AT_BOOL,0,"FALSE",num_lines,NULL,NULL,NULL,NULL);}
;

ExprG :
      Id          {$$=$1;}
;

ExprD :
      ExprG                                     {$$=$1;}
      | CallFonction                            {$$=$1;}
      | ExprD PLUS ExprD                        {$$=createNode(AT_ADD,0,"",$1->line,$1,$3,NULL,NULL);}
      | ExprD MINUS ExprD                       {$$=createNode(AT_MIN,0,"",$1->line,$1,$3,NULL,NULL);}
      | ExprD TIMES ExprD                       {$$=createNode(AT_MUL,0,"",$1->line,$1,$3,NULL,NULL);}
      | ExprD MODULO ExprD                      {$$=createNode(AT_MOD,0,"",$1->line,$1,$3,NULL,NULL);}
      | ExprD SLASHORDIV ExprD                  {$$=createNode(AT_DIV,0,"",$1->line,$1,$3,NULL,NULL);}
      | ExprD AND ExprD                         {$$=createNode(AT_AND,0,"",$1->line,$1,$3,NULL,NULL);}
      | ExprD OR ExprD                          {$$=createNode(AT_OR,0,"",$1->line,$1,$3,NULL,NULL);}
      | NOT ExprD                               {$$=createNode(AT_NOT,0,"",$2->line,$2,NULL,NULL,NULL);}
      | Nb                                      {$$=$1;}
      | ExprD EQUAL ExprD                       {$$=createNode(AT_EQUAL,0,"",$1->line,$1,$3,NULL,NULL);}
      | ExprD SMALLER ExprD                     {$$=createNode(AT_SMALLER,0,"",$1->line,$1,$3,NULL,NULL);}
      | ExprD SMALLEQ ExprD                     {$$=createNode(AT_SMALLEQ,0,"",$1->line,$1,$3,NULL,NULL);}
      | ExprD GREATER ExprD                     {$$=createNode(AT_GREATER,0,"",$1->line,$1,$3,NULL,NULL);}
      | ExprD GREATEQ ExprD                     {$$=createNode(AT_GREATEQ,0,"",$1->line,$1,$3,NULL,NULL);}
      | LP ExprD RP                             {$$=$2;}
      | True                                    {$$=$1;}
      | False                                   {$$=$1;}
      | GET LP Id COMMA ExprD COMMA ExprD RP    {$$=createNode(AT_GET,0,"",$3->line,$3,$5,$7,NULL);}
      | IN                                      {$$=createNode(AT_IN,0,"int",num_lines,NULL,NULL,NULL,NULL);}
;

%%


void yyerror(char *str)
{
        printf("; SYNTAX ERROR '%s' AT LINE  %d : UNRECOGNISED '%s'\n", str,num_lines,yytext);
        fprintf(stderr,"KO\n");
        exit(0);
}

void yyerrorFct(char *str)
{
        printf("; SYNTAX ERROR : Probleme de balise de fonction : %s \n", str);
        fprintf(stderr,"KO\n");
        exit(0);
}

void yyerrorTypage(char *str)
{
        printf("; TYPE ERROR \n");
        fprintf(stderr,"KO\n");
        exit(0);
}

int main()
{
        yyparse();

        //printf("\n\n");
        printf(";######################Tree#######################\n");
        //printTree(root);

        symTable = createSymTable();
        
        fillSymTableWithFonction(symTable,root, 0, root->name);//remplir la table

        //printf("\n\n");
        printf(";######################SymTable#######################\n");
        //printSymbolTable(symTable);

        
        //printf("\n\n");
        printf(";######################CheckAllFct#######################\n");
        if (checkAllFct(symTable->childFct, symTable) == 0)
          yyerrorTypage("");

	printf("\n;*** BEGIN PCodeGeneration ***\n");
	pcodeGenValue(root, symTable);
	printf(";*** END PCodeGeneration ***\n");
	
	printf(";*** BEGIN Cleaning ***\n");
 	freeTree(root);
	freeSymTableFct(symTable);
  	printf(";*** END Cleaning ***\n");

        fprintf(stderr,"OK\n");
        return 0;
}




